package ec;

import ge.CodonIterator;

import java.util.BitSet;
import java.util.Iterator;

import org.apache.log4j.Logger;

/**
 * Given a BitSolution return an iterator that goes over the solution turning
 * blocks of a given size into integers.
 * 
 * @author Nathaniel Troutman
 */
public class BitBlockIterator implements Iterator<Integer> {

	private static Logger LOG = Logger.getLogger(CodonIterator.class);
	protected BitSet _bits = null;
	protected int _block_length = 0;
	private int _index = 0;
	protected int _num_bits = 0;
	private int _num_calls = 0;

	public BitBlockIterator(BitSolution solution) {
		_bits = solution._bits;
		_num_bits = _bits.size();
		_block_length = solution._block_length;
	}
	
	public BitBlockIterator(BitSolution solution, int block_size) {
		_bits = solution._bits;
		_num_bits = _bits.size();
		_block_length = block_size;
	}

	public boolean hasNext() {
		// Since we loop around the end we always have a next
		return true;
	}

	public Integer next() {
		_num_calls++;
	
		// Calc the value
		int value = 0;
	
		// Loop over the bits reconstructing the value
		for (int i = 0; i < _block_length; i++) {
			// shift the current value over one bit in preparation for appending
			// the next one
			value = value << 1;
	
			// "append" the next bit
			if (_bits.get(_index++)) {
				value |= 0x1;
			}
	
			// wrap around
			if (_index == _num_bits) {
				_index = 0;
			}
		}
	
		return value;
	}

	public Integer nextOld() {
		int stop_index = _index + _block_length;
	
		// If we exceed the length wrap around
		if (stop_index >= _num_bits) {
			_index = 0;
			stop_index = _block_length;
		}
	
		// Calc the value
		int value = 0;
		// Loop over the bits reconstructing the value
		for (int i = _index; i < stop_index; i++) {
			// shift the current value over one bit in preparation for appending
			// the next one
			value = value << 1;
	
			// "append" the next bit
			if (_bits.get(i)) {
				value |= 0x1;
			}
		}
	
		if (false && LOG.isTraceEnabled()) {
			StringBuilder str = new StringBuilder();
			for (int i = _index; i < stop_index; i++) {
				str.append((_bits.get(i) ? '1' : '0'));
			}
	
			LOG.trace("stop_index=" + stop_index + " value=" + value + " bits="
					+ str);
	
			str = new StringBuilder();
			int debug_value = 0;
			for (int i = _index; i < stop_index; i++) {
				debug_value = debug_value << 1;
	
				str.append((_bits.get(i) ? '1' : '0'));
				if (_bits.get(i)) {
					debug_value |= 0x1;
				}
	
				LOG.trace("\t" + str + "=" + debug_value);
			}
		}
	
		_index = stop_index;
	
		return value;
	}

	public void remove() {
	}

	public int getNumCalls() {
		return _num_calls;
	}

}